# -*- coding: utf-8 -*-

import os
import re
import time
import json
import ppc
import ppc.pipe


class RangeExtracter(ppc.pipe.Pipe):
    """范围选择提取器"""

    def handle(self):
        input = self['source'].value if 'source' in self else self.input

        if 'multiple' not in self \
            or self['multiple'].value.lower() != 'yes':
            multiple = False
        else:
            multiple = True

        start = 0
        while True:
            postions = []

            for name in ['begin', 'end']:
                child = self[name]
                type = child['type'] if 'type' in child else 'equal'
                p = self._find(input, child['value'], start, type)

                if p[0] == -1:
                    return

                postions.append(p)
                start = p[1]

            self.transfer(input[postions[0][1]:postions[1][0]])

            if not multiple:
                break

            # 是否循环中止
            if self.flag == ppc.pipe.Flag.Break:
                self.flag = ppc.pipe.Flag.Normal
                break

    def _find(self, string, sub, start, match):
        mt = '_match{0}'.format(match.capitalize())
        if hasattr(self, mt):
            method = getattr(self, mt)
            (p1, p2) = method(string[start:], sub)
            if p1 != -1:
                return (p1 + start, p2 + start)   
        return (-1, -1)

    def _matchEqual(self, string, sub):
        b = string.find(sub)
        e = b + len(sub)
        return (b, e) if b != -1 else (-1, -1)

    def _matchRegex(self, string, pattern):
        m = re.search(pattern, string)
        return m.span() if m else (-1, -1)


class TagExtracter(ppc.pipe.Pipe):
    """
    标签匹配提取器

    TODO: 标签嵌套的处理
    """

    def handle(self):
        input = self['source'].value if 'source' in self else self.input

        tag = self['tag'].value
        limit = int(self['limit'].value) if 'limit' in self else 2147483647

        start = 0
        while limit > 0:
            # 每一个标签
            d = {}
            tb1 = input.find('<' + tag, start)
            if tb1 == -1:
                break
            p = tb1 + len(tag) + 1
            # 标签内的每一属性
            while 1:
                while input[p].isspace():
                    p += 1
                ab1 = -1
                ab2 = -1
                if input[p].isalnum() or input[p] == '_':
                    ab1 = p
                    while input[p].isalnum() or input[p] == '-' or input[p] == '_':
                        p += 1
                    ab2 = p
                while input[p].isspace():
                    p += 1
                if input[p] == '=':
                    p += 1
                    while input[p].isspace():
                        p += 1
                    if input[p] == "'" or input[p] == '"':
                        quot = input[p]
                        p += 1
                        ab3 = p
                        while input[p] != quot:
                            p += 1
                        ab4 = p
                        attr = input[ab1:ab2]
                        value = input[ab3:ab4]
                        d[attr] = value
                        p += 1
                    else:
                        ab3 = p
                        while (not input[p].isspace()) and input[p] != '>':
                            p += 1
                        ab4 = p
                        attr = input[ab1:ab2]
                        value = input[ab3:ab4]
                        d[attr] = value
                elif ab1 != -1 and ab2 != -1:
                    attr = input[ab1:ab2]
                    d[attr] = True

                if input[p] == '>':
                    p += 1
                    tb2 = p
                    break
                elif not input[p].isspace():
                    p = input.find('>', p)
                    p += 1
                    tb2 = p
                    break

            # 标签包含的内容
            if input[tb2-2:tb2] == '/>':
                d['value'] = None
                start = tb2
            else:
                tb3 = input.find('</' + tag + '>', tb2)
                tb4 = tb3 + len(tag) + 3
                if tb3 == -1:
                    d['value'] = None
                    start = tb2
                else:
                    d['value'] = input[tb2:tb3]
                    start = tb4

            # 记数
            limit -= 1

            # 传递
            self.transfer(d)

            # 是否循环中止
            if self.flag == ppc.pipe.Flag.Break:
                self.flag = ppc.pipe.Flag.Normal
                break


class CutExtracter(ppc.pipe.Pipe):
    """某标记之前或之后的内容选择"""

    def handle(self):
        input = self['source'].value if 'source' in self else self.input

        mark = self['mark'].value
        pos = input.find(mark)
        if pos == -1:
            self.transfer(input)
        else:
            if 'reserve' not in self \
                or self['reserve'].value.lower() != 'before':
                # after
                pos += len(mark)
                self.transfer(input[pos:])
            else:
                # before
                self.transfer(input[:pos])


class RegexExtracter(ppc.pipe.Pipe):
    """
    正则匹配提取器
    分别匹配子标签中定义的正则表达式，获取正则中的组名为value的匹配内容为子项的数值
    """

    def handle(self):
        input = self['source'].value if 'source' in self else self.input
        d = {}
        for p in self._params.values():
            match = re.search(p['value'], input)
            d[p.tag] = match.group('value') if match else ''
        self.transfer(d)
            

class CombineExtracter(ppc.pipe.Pipe):
    """
    数据组合器
    在xml配置文件中设置各项参数值，用于数据整合后集中处理
    """

    def handle(self):
        d = {}
        for p in self._params.values():
            d[p.tag] = p['value']
        self.transfer(d)
            

class JsonDecoder(ppc.pipe.Pipe):
    """
    json字符串解析器
    """

    def handle(self):
        input = self['source'].value if 'source' in self else self.input
        o = json.JSONDecoder().decode(input)
        #print(json.dumps(o, sort_keys=True, indent=4, ensure_ascii=False))
        self.transfer(o)


class BytesDecoder(ppc.pipe.Pipe):
    """
    bytes按待定编码解析到str
    """

    def handle(self):
        charset = self['charset'].value if 'charset' in self else 'utf-8'
        str = self.input.decode(charset)
        self.transfer(str)
